import * as path from 'path';
import * as fs from 'fs';
import { Logger } from '../../../../src/logger/Logger';

/**
 * Fuzz Group 定位器
 * 
 * 功能：在项目中智能查找 group("fuzztest") 的 BUILD.gn 位置
 * 
 * 背景：
 * - 一个项目可能有多个 test/fuzztest 目录
 * - Group GN 的位置不固定（可能在 services/、interfaces/ 等）
 * - Fuzzer 和 Group 不一定是父子关系
 * 
 * 策略：
 * 1. 在项目根目录下递归查找所有 test/fuzztest/BUILD.gn
 * 2. 分析每个 BUILD.gn 是否包含 group("fuzztest")
 * 3. 基于路径相似度和模块名推荐最合适的 group
 * 4. 让用户确认（或自动选择）
 */
export class FuzzGroupLocator {
    /**
     * 在项目中查找所有包含 group("fuzztest") 的 BUILD.gn
     * 
     * @param projectRoot 项目根目录
     * @returns 包含 group 的 BUILD.gn 文件列表
     */
    public static findAllFuzzGroups(projectRoot: string): Array<{
        gnPath: string;
        relativePath: string;
        groupName: string;
        depsCount: number;
    }> {
        const groups: Array<{
            gnPath: string;
            relativePath: string;
            groupName: string;
            depsCount: number;
        }> = [];

        this.scanForFuzzGroups(projectRoot, projectRoot, groups);

        Logger.info(`[FuzzGroupLocator] 找到 ${groups.length} 个 fuzztest group`);
        groups.forEach(g => {
            Logger.info(`[FuzzGroupLocator]   - ${g.relativePath} (${g.depsCount} deps)`);
        });

        return groups;
    }

    /**
     * 递归扫描目录，查找包含 group("fuzztest") 的 BUILD.gn
     */
    private static scanForFuzzGroups(
        currentDir: string,
        projectRoot: string,
        results: Array<any>
    ): void {
        if (!fs.existsSync(currentDir)) {
            return;
        }

        try {
            const entries = fs.readdirSync(currentDir, { withFileTypes: true });

            for (const entry of entries) {
                const fullPath = path.join(currentDir, entry.name);

                // 跳过
                if (entry.name.startsWith('.') || 
                    entry.name === 'node_modules' || 
                    entry.name === 'out' ||
                    entry.name === 'build' ||
                    entry.name === 'vendor' ||
                    entry.name === 'third_party') {
                    continue;
                }

                if (entry.isDirectory()) {
                    // 递归扫描
                    this.scanForFuzzGroups(fullPath, projectRoot, results);
                } else if (entry.name === 'BUILD.gn') {
                    // 检查是否包含 group("fuzztest")
                    const groupInfo = this.analyzeGroupInBuildGn(fullPath, projectRoot);
                    if (groupInfo) {
                        results.push(groupInfo);
                    }
                }
            }
        } catch (err) {
            // 跳过无法访问的目录
        }
    }

    /**
     * 分析 BUILD.gn 文件，检查是否包含 group("fuzztest")
     */
    private static analyzeGroupInBuildGn(
        gnPath: string,
        projectRoot: string
    ): {
        gnPath: string;
        relativePath: string;
        groupName: string;
        depsCount: number;
    } | null {
        try {
            const content = fs.readFileSync(gnPath, 'utf-8');

            // 匹配 group("fuzztest") { ... }
            const groupRegex = /group\s*\(\s*["']fuzztest["']\s*\)\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s;
            const match = content.match(groupRegex);

            if (match) {
                const groupBody = match[1];

                // 提取 deps
                const depsRegex = /deps\s*=\s*\[([^\]]*)\]/s;
                const depsMatch = groupBody.match(depsRegex);
                let depsCount = 0;

                if (depsMatch) {
                    const depsStr = depsMatch[1];
                    // 统计 deps 数量（通过逗号或换行分隔）
                    depsCount = (depsStr.match(/["'][^"']+["']/g) || []).length;
                }

                const relativePath = path.relative(projectRoot, gnPath).replace(/\\/g, '/');

                return {
                    gnPath,
                    relativePath,
                    groupName: 'fuzztest',
                    depsCount
                };
            }
        } catch (err) {
            // 跳过读取失败的文件
        }

        return null;
    }

    /**
     * 推荐最合适的 group（基于路径相似度和模块名）
     * 
     * @param fuzzerDir Fuzzer 目录，如 services/audiomanager/test/fuzztest/xxx_fuzzer
     * @param allGroups 所有找到的 group
     * @returns 推荐的 group
     */
    public static recommendBestGroup(
        fuzzerDir: string,
        allGroups: Array<{
            gnPath: string;
            relativePath: string;
            groupName: string;
            depsCount: number;
        }>
    ): {
        gnPath: string;
        relativePath: string;
        score: number;
        reason: string;
    } | null {
        if (allGroups.length === 0) {
            return null;
        }

        if (allGroups.length === 1) {
            return {
                ...allGroups[0],
                score: 100,
                reason: '唯一的 fuzztest group'
            };
        }

        // 计算每个 group 的匹配分数
        const scores = allGroups.map(group => {
            let score = 0;
            let reason = '';

            const fuzzerPathParts = fuzzerDir.toLowerCase().split(/[\\\/]/);
            const groupPathParts = group.relativePath.toLowerCase().split(/[\\\/]/);

            // 策略1：路径前缀匹配（权重：50）
            let commonPrefixLength = 0;
            for (let i = 0; i < Math.min(fuzzerPathParts.length, groupPathParts.length); i++) {
                if (fuzzerPathParts[i] === groupPathParts[i]) {
                    commonPrefixLength++;
                } else {
                    break;
                }
            }
            const prefixScore = (commonPrefixLength / Math.max(fuzzerPathParts.length, groupPathParts.length)) * 50;
            score += prefixScore;

            if (commonPrefixLength > 0) {
                reason = `路径前缀匹配 ${commonPrefixLength} 层`;
            }

            // 策略2：包含相同的模块名（权重：30）
            const fuzzerModules = new Set(fuzzerPathParts.filter(p => 
                !['test', 'fuzztest', 'unittest', 'services', 'interfaces'].includes(p)
            ));
            const groupModules = new Set(groupPathParts.filter(p => 
                !['test', 'fuzztest', 'unittest', 'services', 'interfaces'].includes(p)
            ));

            let commonModules = 0;
            for (const module of fuzzerModules) {
                if (groupModules.has(module)) {
                    commonModules++;
                }
            }

            if (commonModules > 0) {
                const moduleScore = (commonModules / Math.max(fuzzerModules.size, groupModules.size)) * 30;
                score += moduleScore;
                reason += reason ? `, 共享 ${commonModules} 个模块名` : `共享 ${commonModules} 个模块名`;
            }

            // 策略3：优先选择 deps 较多的 group（说明是主 group）（权重：20）
            if (group.depsCount > 5) {
                score += 20;
                reason += reason ? ', 主 group（deps > 5）' : '主 group（deps > 5）';
            } else if (group.depsCount > 0) {
                score += 10;
                reason += reason ? ', 次要 group' : '次要 group';
            }

            return {
                ...group,
                score,
                reason: reason || '默认匹配'
            };
        });

        // 排序并返回得分最高的
        scores.sort((a, b) => b.score - a.score);

        const best = scores[0];
        Logger.info(`[FuzzGroupLocator] 推荐 group: ${best.relativePath} (得分: ${best.score.toFixed(1)}, 原因: ${best.reason})`);

        return best;
    }

    /**
     * 获取 group 的目录（用于计算相对路径）
     */
    public static getGroupDirectory(groupGnPath: string): string {
        return path.dirname(groupGnPath);
    }

    /**
     * 计算 fuzzer 相对于 group 的路径
     * 
     * @param fuzzerDir Fuzzer 目录
     * @param groupGnPath Group BUILD.gn 路径
     * @returns 相对路径，用于 deps
     */
    public static calculateRelativePath(fuzzerDir: string, groupGnPath: string): string {
        const groupDir = path.dirname(groupGnPath);
        const relativePath = path.relative(groupDir, fuzzerDir).replace(/\\/g, '/');
        
        Logger.info(`[FuzzGroupLocator] 计算相对路径:`);
        Logger.info(`[FuzzGroupLocator]   Fuzzer: ${fuzzerDir}`);
        Logger.info(`[FuzzGroupLocator]   Group: ${groupDir}`);
        Logger.info(`[FuzzGroupLocator]   相对路径: ${relativePath}`);
        
        return relativePath;
    }

    /**
     * 格式化 dep 路径（用于添加到 group 的 deps）
     * 
     * @param relativePath 相对路径
     * @param targetName 目标名称
     * @returns 格式化的 dep，如 "../../../services/audiomanager/test/fuzztest/xxx_fuzzer:XxxFuzzerTest"
     */
    public static formatDepPath(relativePath: string, targetName: string): string {
        // 如果是当前目录下的子目录，使用 "./" 前缀
        if (!relativePath.startsWith('..') && !relativePath.startsWith('/')) {
            return `./${relativePath}:${targetName}`;
        }
        
        // 否则使用完整相对路径
        return `${relativePath}:${targetName}`;
    }
}

